package cn.jetpiece.cloud.core.util;

import cn.hutool.core.util.StrUtil;
import cn.jetpiece.cloud.config.properties.JetpieceGatewayProperties;
import cn.jetpiece.cloud.core.consts.GatewayConstants;
import cn.jetpiece.cloud.core.exception.enums.GatewayExceptionEnum;
import cn.jetpiece.cloud.jwt.utils.JwtTokenUtil;
import cn.jetpiece.cloud.modular.cache.ResourceServiceCache;
import cn.jetpiece.cloud.resource.annotation.keys.ResourceKey;
import cn.jetpiece.cloud.resource.annotation.model.ResourceParam;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.PathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;

/**
 * 网关校验工具类
 *
 * @author XuJZ
 */
public class AuthenticationUtils {

    public static boolean urlIgnore(String serverCode, String path) {
        List<String> ignoreUrls = JetpieceGatewayProperties.getInstance().getServerIgnoreUrl().get(serverCode);
        if (ignoreUrls != null) {
            for (String ignoreUrl : ignoreUrls) {
                if (path.startsWith(ignoreUrl)) {
                    return true;
                }
            }
        }
        List<String> ignoreUrlEnds = JetpieceGatewayProperties.getInstance().getServerIgnoreUrlEnd().get(serverCode);
        if (ignoreUrlEnds != null) {
            for (String ignoreUrlEnd : ignoreUrlEnds) {
                if (path.endsWith(ignoreUrlEnd)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     * 获取当前网关基础Url
     *
     * @param exchange 请求信息
     * @return 网关基础Url
     */
    public static String getGatewayBaseUrl(ServerWebExchange exchange) {
        ServerHttpRequest request = exchange.getRequest();
        String host;
        String forwardedHost = request.getHeaders().getFirst("X-Forwarded-Host");
        if (StringUtils.hasText(forwardedHost)) {
            host = forwardedHost.contains(",") ? forwardedHost.split(",")[0] : forwardedHost;
        } else {
            host = request.getURI().getHost() + ":" + exchange.getRequest().getURI().getPort();
        }
        String proto;
        String forwardedProto = request.getHeaders().getFirst("X-Forwarded-Proto");
        if (StringUtils.hasText(forwardedProto)) {
            proto = forwardedProto.contains(",") ? forwardedProto.split(",")[0] : forwardedProto;
        } else {
            proto = exchange.getRequest().getURI().getScheme();
        }
        return proto + "://" + host;
    }

    /**
     * 获取请求中token,获取不到返回空串
     *
     * @param request 请求
     * @return token
     */
    public static String getToken(ServerHttpRequest request) {
        //设置token
        String token = request.getHeaders().getFirst(GatewayConstants.AUTH_HEADER);
        if (StrUtil.isBlank(token)) {
            token = request.getQueryParams().getFirst(GatewayConstants.PARAMS_TOKEN);
        }
        if (StrUtil.isBlank(token)) {
            token = "";
        } else {
            token = delTokenHeader(token);
        }
        return token;
    }

    /**
     * 删除token头部 Bearer
     *
     * @param token token值
     * @return 去除头部后值
     */
    public static String delTokenHeader(String token) {
        if (token.startsWith("Bearer")) {
            token = token.substring(7);
        }
        return token;
    }

    /**
     * 获取资源信息
     *
     * @param request 请求
     * @return 资源信息
     */
    public static ResourceParam getResource(ServerHttpRequest request) {
        String serverCode = request.getHeaders().getFirst(ResourceKey.REQUEST_SERVER_CODE);
        String resourceKey = request.getHeaders().getFirst(ResourceKey.REQUEST_RESOURCE_KEY);
        return ResourceServiceCache.getINSTANCE().getResourceByUrl(serverCode, resourceKey);
    }

    /**
     * 获取资源缓存标识
     *
     * @param serverCode 服务编码
     * @param path       路径
     * @return 资源标识
     */
    public static String getResourceKey(String serverCode, String path) {
        Set<Object> urls = ResourceServiceCache.getINSTANCE().getResourceByCode(serverCode);
        /* 获取资源Key */
        PathMatcher pathMatcher = new AntPathMatcher();
        List<String> hitUrl = new ArrayList<>();
        for (Object url : urls) {
            if (path.equals(url)) {
                return url.toString();
            }
            if (pathMatcher.match(url.toString(), path)) {
                hitUrl.add(url.toString());
            }
        }
        return hitUrl.isEmpty() ? "" : hitUrl.get(0);
    }

    /**
     * 校验请求中的token，有异常返回异常枚举，无异常返回空
     *
     * @param request 请求信息
     * @return 异常枚举
     */
    public static GatewayExceptionEnum checkToken(ServerHttpRequest request) {
        /* 获取资源信息 */
        ResourceParam resourceParam = getResource(request);
        return checkToken(request, resourceParam);
    }

    /**
     * 校验请求中的token，有异常返回异常枚举，无异常返回空
     *
     * @param request       请求信息
     * @param resourceParam 资源信息
     * @return 异常枚举
     */
    public static GatewayExceptionEnum checkToken(ServerHttpRequest request, ResourceParam resourceParam) {
        //获取token
        String token = request.getHeaders().getFirst(GatewayConstants.AUTH_HEADER);
        GatewayExceptionEnum anEnum = checkToken(token);
        if (anEnum == null) {
            return null;
        }
        GatewayExceptionEnum resourceEnum = checkResource(resourceParam);
        return resourceEnum == null ? null : anEnum;
    }

    /**
     * 检验资源，有异常返回异常枚举，无异常返回空
     *
     * @param resourceParam 资源信息
     * @return 异常枚举
     */
    public static GatewayExceptionEnum checkResource(ResourceParam resourceParam) {
        if (resourceParam == null) {
            return GatewayExceptionEnum.NO_PERMISSION;
        }
        /* 内部请求 */
        if (resourceParam.getInternal()) {
            return GatewayExceptionEnum.NO_PERMISSION;
        }
        /* 资源存在免鉴权 */
        if (resourceParam.getRequiredLoginFlag().equals("Y")) {
            return GatewayExceptionEnum.NO_PERMISSION;
        }
        return null;
    }

    /**
     * 校验token值，有异常返回异常枚举，无异常返回空
     *
     * @param token token值
     * @return 异常枚举
     */
    public static GatewayExceptionEnum checkToken(String token) {
        if (StrUtil.isBlank(token)) {
            return GatewayExceptionEnum.TOKEN_EMPTY;
        }
        if (!JwtTokenUtil.getINSTANCE().checkToken(token)) {
            return GatewayExceptionEnum.TOKEN_ERROR;
        }
        return null;
    }
}
